package parser

import (
	

	
)

type stateType int

const (
	defState stateType = iota
	xpathState
	funcState
	paramState
	predState
	parenState
)

type parseStack struct {
	stack      []*Node
	stateTypes []stateType
	cur        *Node
}

func ( *parseStack) ( stateType) {
	.stack = append(.stack, .cur)
	.stateTypes = append(.stateTypes, )
}

func ( *parseStack) () {
	 := len(.stack) - 1

	.cur = .stack[]
	.stack = .stack[:]
	.stateTypes = .stateTypes[:]
}

func ( *parseStack) () stateType {
	if len(.stateTypes) == 0 {
		return defState
	}
	return .stateTypes[len(.stateTypes)-1]
}

type lexFn func(*parseStack, lexer.XItem)

var parseMap = map[lexer.XItemType]lexFn{
	lexer.XItemAbsLocPath:     xiXPath,
	lexer.XItemAbbrAbsLocPath: xiXPath,
	lexer.XItemAbbrRelLocPath: xiXPath,
	lexer.XItemRelLocPath:     xiXPath,
	lexer.XItemEndPath:        xiEndPath,
	lexer.XItemAxis:           xiXPath,
	lexer.XItemAbbrAxis:       xiXPath,
	lexer.XItemNCName:         xiXPath,
	lexer.XItemQName:          xiXPath,
	lexer.XItemNodeType:       xiXPath,
	lexer.XItemProcLit:        xiXPath,
	lexer.XItemFunction:       xiFunc,
	lexer.XItemArgument:       xiFuncArg,
	lexer.XItemEndFunction:    xiEndFunc,
	lexer.XItemPredicate:      xiPred,
	lexer.XItemEndPredicate:   xiEndPred,
	lexer.XItemStrLit:         xiValue,
	lexer.XItemNumLit:         xiValue,
	lexer.XItemOperator:       xiOp,
	lexer.XItemVariable:       xiValue,
}

var opPrecedence = map[string]int{
	"|":   1,
	"*":   2,
	"div": 2,
	"mod": 2,
	"+":   3,
	"-":   3,
	"=":   4,
	"!=":  4,
	"<":   4,
	"<=":  4,
	">":   4,
	">=":  4,
	"and": 5,
	"or":  6,
}

//Parse creates an AST tree for XPath expressions.
func ( string) (*Node, error) {
	var  error
	 := lexer.Lex()
	 := &Node{}
	 := &parseStack{cur: }

	for  := range  {
		if .Typ != lexer.XItemError {
			parseMap[.Typ](, )
		} else if  == nil {
			 = fmt.Errorf(.Val)
		}
	}

	return , 
}

func xiXPath( *parseStack,  lexer.XItem) {
	if .curState() == xpathState {
		.cur.push()
		.cur = .cur.next
		return
	}

	if .cur.Val.Typ == lexer.XItemFunction {
		.cur.Right = &Node{Val: , Parent: .cur}
		.cur.next = .cur.Right
		.push(xpathState)
		.cur = .cur.next
		return
	}

	.cur.pushNotEmpty()
	.push(xpathState)
	.cur = .cur.next
}

func xiEndPath( *parseStack,  lexer.XItem) {
	.pop()
}

func xiFunc( *parseStack,  lexer.XItem) {
	if .cur.Val.Typ == Empty {
		.cur.pushNotEmpty()
		.push(funcState)
		.cur = .cur.next
		return
	}
	.cur.push()
	.cur = .cur.next
	.push(funcState)
}

func xiFuncArg( *parseStack,  lexer.XItem) {
	if .curState() != funcState {
		.pop()
	}

	.cur.push()
	.cur = .cur.next
	.push(paramState)
	.cur.push(lexer.XItem{Typ: Empty, Val: ""})
	.cur = .cur.next
}

func xiEndFunc( *parseStack,  lexer.XItem) {
	if .curState() == paramState {
		.pop()
	}
	.pop()
}

func xiPred( *parseStack,  lexer.XItem) {
	.cur.push()
	.cur = .cur.next
	.push(predState)
	.cur.push(lexer.XItem{Typ: Empty, Val: ""})
	.cur = .cur.next
}

func xiEndPred( *parseStack,  lexer.XItem) {
	.pop()
}

func xiValue( *parseStack,  lexer.XItem) {
	.cur.add()
}

func xiOp( *parseStack,  lexer.XItem) {
	if .Val == "(" {
		.cur.push(lexer.XItem{Typ: Empty, Val: ""})
		.push(parenState)
		.cur = .cur.next
		return
	}

	if .Val == ")" {
		.pop()
		return
	}

	if .cur.Val.Typ == lexer.XItemOperator {
		if opPrecedence[.cur.Val.Val] <= opPrecedence[.Val] {
			.cur.add()
		} else {
			.cur.push()
		}
	} else {
		.cur.add()
	}
	.cur = .cur.next
}